<?php
/**
 * 分布式redis
 */

namespace app\common\model;

/**
 * Created by PhpStorm.
 * User: openspring
 * Date: 2018/3/17
 * Time: 09:26
 */

class RedisModel
{

    private static $_db;
    private static $_db_to_position;
    private static $_position_to_db;
    private static $_slave_db;

    private static function _hash($key)
    {
        return md5($key);
    }

    private static function getMasterConfig()
    {
        return config('redis.redis_nodes');
    }

    private static function getSlaveConfig()
    {
        return config('redis.redis_slave_nodes');

    }

    /**
     * @param $key
     * @return \Redis mixed
     */
    public static function db($key)
    {
        $master_config = self::getMasterConfig();
        if (empty($master_config)) {
            abort(500, 'redis配置错误');
        }

        return self::getConnection($master_config, $key);
    }

    public static function slave_db($key)
    {
        $slave_config = self::getSlaveConfig();
        if (empty($slave_config)) {
            abort(500, 'redis配置错误');
        }

        return self::getConnection($slave_config, $key);
    }

    public static function getConnection($config, $key)
    {
        if (empty(self::$_db)) {
            foreach ($config as $node) {
                $db = new \Redis();
                $db->pconnect($node['host'], $node['port']);
                $db->auth($node['pwd']);
                $name = $node['host'] . $node['port'];
                $db_key = self::_hash($name);
                self::$_db[$db_key] = $db;

                for ($i = 0; $i < 3; $i++) {
                    $position = self::_hash($name . '#' . $i);
                    self::$_position_to_db[$position] = $db_key;
                    self::$_db_to_position[$db_key][] = $position;
                }
            }
            asort(self::$_position_to_db);
        }

        $target = null;
        $position_key = self::_hash($key);
        foreach (self::$_position_to_db as $pos => $db_key) {
            if (empty($target)) {
                $target = $db_key;
            }
            if ($position_key < $pos) {
                $target = $db_key;
            }
        }
        return self::$_db[$target];
    }

    public static function close()
    {
        if (self::$_db) {
            foreach (self::$_db as $db) {
                /** @var $db \Redis */
                $db->close();
            }
        }
    }

    public static function slave_close()
    {
        if (self::$_slave_db) {
            foreach (self::$_slave_db as $db) {
                /** @var $db \Redis */
                $db->close();
            }
        }
    }

}